package com.godyao.framework.beans.factory.xml;

import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.XmlUtil;
import com.godyao.framework.beans.BeansException;
import com.godyao.framework.beans.PropertyValue;
import com.godyao.framework.beans.factory.config.BeanDefinition;
import com.godyao.framework.beans.factory.factory.BeanReference;
import com.godyao.framework.beans.factory.support.AbstractBeanDefinitionReader;
import com.godyao.framework.beans.factory.support.BeanDefinitionRegistry;
import com.godyao.framework.context.annotation.ClassPathBeanDefinitionScanner;
import com.godyao.framework.core.io.Resource;
import com.godyao.framework.core.io.ResourceLoader;
import org.dom4j.Attribute;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.io.SAXReader;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * 加载xml文件解析并注册bean
 * @author missw
 */
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry, ResourceLoader resourceLoader) {
        super(registry, resourceLoader);
    }

    public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
        super(registry);
    }

    @Override
    public void loadBeanDefinitions(Resource resource) {
        try {
            try(InputStream inputStream = resource.getInputStream()){
                doLoadBeanDefinitions(inputStream);
            }
        } catch (IOException | ClassNotFoundException | DocumentException e) {
            throw new BeansException("IOException parsing XML document from " + resource, e);
        }

    }

    @Override
    public void loadBeanDefinitions(Resource... resources) {
        for (Resource resource : resources) {
            loadBeanDefinitions(resource);
        }
    }

    @Override
    public void loadBeanDefinitions(String location) {
        ResourceLoader resourceLoader = getResourceLoader();
        Resource resource = resourceLoader.getResource(location);
        loadBeanDefinitions(resource);
    }

    @Override
    public void loadBeanDefinitions(String[] locations) {
        ResourceLoader resourceLoader = getResourceLoader();
        for (String location : locations) {
            Resource resource = resourceLoader.getResource(location);
            loadBeanDefinitions(resource);
        }
    }


    /**
     * 解析资源加载bean注册信息的具体实现
     * @param inputStream
     */
//    private void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException {
//        Document document = XmlUtil.readXML(inputStream);
//        Element rootElement = document.getDocumentElement();
//        NodeList childNodes = rootElement.getChildNodes();
//
//        for (int i = 0; i < childNodes.getLength(); i++) {
//            Node item = childNodes.item(i);
//            // 跳过不满足条件的element
//            if (!(item instanceof Element)) {
//                continue;
//            }
//            if (!"bean".equals(item)) {
//                continue;
//            }
//            // 解析标签
//            Element bean = (Element) item;
//            String id = bean.getAttribute("id");
//            String name = bean.getAttribute("name");
//            String aClass = bean.getAttribute("class");
//            // 反射获取class
//            Class<?> clazz = Class.forName(aClass);
//            // beanName优先取id
//            String beanName = StrUtil.isNotBlank(id) ? id : name;
//            if (StrUtil.isBlank(beanName)) {
//                // 类名首字母小写作为beanName
//                beanName = StrUtil.lowerFirst(clazz.getSimpleName());
//            }
//            //定义Bean
//            BeanDefinition beanDefinition = new BeanDefinition(clazz);
//            //读取并填充属性
//            for (int i1 = 0; i1 < bean.getChildNodes().getLength(); i1++) {
//                Node propertyNode = bean.getChildNodes().item(i);
//                // 跳过不满足条件的element
//                if (!(propertyNode instanceof Element)) {
//                    continue;
//                }
//                if (!"property".equals(propertyNode)) {
//                    continue;
//                }
//                // 解析 标签property
//                Element property = (Element) propertyNode;
//                String attrName = property.getAttribute("name");
//                String attrValue = property.getAttribute("value");
//                String attrRef = property.getAttribute("ref");
//                // 获取属性值
//                Object value = StrUtil.isNotBlank(attrRef) ? new BeanReference(attrRef) : attrValue;
//                //创建属性信息
//                PropertyValue propertyValue = new PropertyValue(attrName, value);
//                beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
//            }
//            if (getRegistry().containsBeanDefinition(beanName)) {
//                throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
//            }
//            // 注册BeanDefinition到DefaultListableBeanFactory.beanDefinitionMap
//            getRegistry().registerBeanDefinition(beanName, beanDefinition);
//        }
//    }
    private void doLoadBeanDefinitions(InputStream inputStream) throws ClassNotFoundException, DocumentException {
        Document read = new SAXReader().read(inputStream);
        org.dom4j.Element rootElement = read.getRootElement();
//        Document document = XmlUtil.readXML(inputStream);
//        Element rootElement = document.getDocumentElement();
        List elements = rootElement.selectNodes("bean");
        org.dom4j.Element componentScanElement = rootElement.element("component-scan");
        if (null != componentScanElement) {
            String classpath = componentScanElement.attributeValue("base-package");
            if (StrUtil.isBlank(classpath)) {
                throw new BeansException("The value of base-package attribute can not be empty or null");
            }
            scanPackage(classpath);
        }



        for (int i = 0; i < elements.size(); i++) {
            org.dom4j.Element bean = (org.dom4j.Element) elements.get(i);
            // 解析标签
            String id = bean.attributeValue("id");
            String name = bean.attributeValue("name");
            String aClass = bean.attributeValue("class");

            // 反射获取class
            Class<?> clazz = Class.forName(aClass);
            // beanName优先取id
            String beanName = StrUtil.isNotBlank(id) ? id : name;
            if (StrUtil.isBlank(beanName)) {
                // 类名首字母小写作为beanName
                beanName = StrUtil.lowerFirst(clazz.getSimpleName());
            }
            //定义bd
            BeanDefinition beanDefinition = new BeanDefinition(clazz);
            String initMethodName = bean.attributeValue("init-method");
            String destroyMethodName = bean.attributeValue("destroy-method");
            String beanScope = bean.attributeValue("scope");
            // 解析初始化方法和销毁方法
            beanDefinition.setInitMethodName(initMethodName);
            beanDefinition.setDestroyMethodName(destroyMethodName);
            beanDefinition.setScope(beanScope == null ? "singleton" : beanScope);
            List<org.dom4j.Element> properties = bean.selectNodes("property");
            //读取并填充属性
            for (int i1 = 0; i1 < properties.size(); i1++) {
                org.dom4j.Element property = properties.get(i1);
                // 解析 标签property
                String attrName = property.attributeValue("name");
                String attrValue = property.attributeValue("value");
                String attrRef = property.attributeValue("ref");

                // 获取属性值 attrRef优先级比attrValue高
                Object value = StrUtil.isNotBlank(attrRef) ? new BeanReference(attrRef) : attrValue;
                //创建属性信息
                PropertyValue propertyValue = new PropertyValue(attrName, value);
                beanDefinition.getPropertyValues().addPropertyValue(propertyValue);
            }
            if (getRegistry().containsBeanDefinition(beanName)) {
                throw new BeansException("Duplicate beanName[" + beanName + "] is not allowed");
            }
            // 注册BeanDefinition到DefaultListableBeanFactory.beanDefinitionMap
            getRegistry().registerBeanDefinition(beanName, beanDefinition);
        }
    }

    private void scanPackage(String classpath) {
        String[] basePackages = StrUtil.splitToArray(classpath, ',');
        ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner = new ClassPathBeanDefinitionScanner(getRegistry());
        classPathBeanDefinitionScanner.doScan(basePackages);

    }

}
